#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
#include <unordered_map>
#include "Common.h"
const std::string Sep = "\r\n";
const std::string BlankLine = Sep;
const std::string HeaderLineSep = ": ";
const std::string LineSep = " ";
const std::string http_version = "HTTP/1.0";
const std::string defaulthomepage = "wwwroot";
const std::string page404 = "wwwroot/404.html";
const std::string firstpage = "index.html";
class HttpRequest
{
public:
    HttpRequest() {}
    ~HttpRequest() {}
    bool IsHasArgs()
    {
        return _isexec;
    }

    bool ParseHeaderkv() // 构造key--value结构
    {
        std::string header, key, value;
        for (auto &line : _req_headers)
        {
            if (SplitString(header, HeaderLineSep, &key, &value))
            {
                _headerkv[key] = value;
            }
        }
        return true;
    }
    bool ParseHeader(std::string &req_str)
    {
        std::string line;
        while (true)
        {
            bool r = ParseOneLine(req_str, &line, Sep);
            if (r && !line.empty())
            {
                _req_headers.push_back(line);
            }
            else if (r && line.empty())
            {
                _blank_line = Sep;
                break;
            }
            else
                return false;
        }
        ParseHeaderkv();
        return true;
    }
    void Deserialize(std::string &req_str) // 反序列化
    {
        if (ParseOneLine(req_str, &_req_line, Sep))
        {
            // 提取请求行当中的详细字段
            ParseReqLine(_req_line, LineSep);
            // 解析请求报头
            ParseHeader(req_str);
            // 剩下的就是正文
            _body = req_str;
        }

        // 分析请求中，是否含有参数
        if (_method == "POST")
        {
            _isexec = true; // 参数在正文
            _args = _body;  // 正文就是参数
            _path = _uri;   // 路径就是请求的uri
        }
        else if (_method == "GET")
        {
            auto pos = _uri.find('?');
            if (pos != std::string::npos)
            {
                // method为GET，有参数
                _isexec = true;
                // login?name=zhangsan&pwd=123456
                _path = _uri.substr(0, pos); // 拿到?的左半部分，拿到左半部分，就可以在httpserver当中，根据这个_path来进行功能路由
                                             // 让它直接执行上层的处理应答的方法，也就是_path就是_route的key
                _args = _uri.substr(pos + 1); // 拿到?的右半部分，就是参数部分，将其保存到_args中
            }
        }
    }
    std::string GetContent(const std::string &path) // 获取用户想要的文件的内容
    {
        // 以二进制方式读
        std::string content;
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return std::string();
        in.seekg(0, in.end);       // 把读写位置定位到文件结束处
        int filesize = in.tellg(); // 获取该位置的偏移量，即文件大小
        in.seekg(0, in.beg);       // 把读写位置回归到文件开始处
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);
        in.close();

        return content;
        // 以文本形式读
        //  std::string content;
        //  std::ifstream in(_uri);
        //  if (!in.is_open())
        //      return std::string();
        //  std::string line;
        //  //这样的读取方式，对于二进制格式的文件来说，会有读取错误，图片就是二进制的，所以这样读文件的话，图片是无法正确读取的
        //  while (std::getline(in, line))
        //  {
        //      content += line;
        //  }
        //  in.close();
        //  return content;
    }
    void Print()
    {
        std::cout << "_method: " << _method << std::endl;
        std::cout << "_uri: " << _uri << std::endl;
        std::cout << "_version: " << _version << std::endl;
        for (auto &[k, v] : _headerkv)
        {
            std::cout << k << ": " << v << std::endl;
        }
        std::cout << "_blank_line: " << _blank_line << std::endl;
        std::cout << "_body: " << _body << std::endl;
    }
    std::string Uri()
    {
        return _uri;
    }
    void SetUri(const std::string &newuri)
    {
        _uri = newuri;
    }
    std::string Path()
    {
        return _path;
    }
    std::string Args()
    {
        return _args;
    }
    std::string Suffix() // 获取文件名后缀，来识别文件类型
    {
        // _uri -> wwwroot/index.html wwwroot/image/1.jpg
        auto pos = _uri.rfind('.');
        if (pos == std::string::npos)
            return std::string(".html");
        else
            return _uri.substr(pos);
    }

private:
    void ParseReqLine(std::string &req_line, const std::string &sep)
    {
        std::stringstream ss(req_line);
        ss >> _method >> _uri >> _version; // 以空格为分隔符，快速写到三个字段里
    }
    std::string _req_line;
    std::vector<std::string> _req_headers;
    std::string _blank_line;
    std::string _body; // body内部，可能会包含参数

    // 在反序列化的过程中，细化我们解析出来的字段
    std::string _method;
    std::string _uri; // 用户请求的资源 部分就是放在这里的，可能也会包含参数
    std::string _path;
    std::string _args;
    std::string _version;
    std::unordered_map<std::string, std::string> _headerkv;
    bool _isexec = false; // 是否需要服务器执行
};
class HttpResponse
{
public:
    HttpResponse() : _version(http_version), _blank_line(BlankLine)
    {
    }
    ~HttpResponse()
    {
    }
    void Build(HttpRequest &req)
    {
        std::string uri = defaulthomepage + req.Uri(); // 补全默认的主页路径
        if (uri.back() == '/')                         // 如果用户请求的uri以/结尾(类似http://124.71.76.44:8080/)，则将其改成访问首页
        {
            uri += firstpage;
            req.SetUri(uri);
        }
        _content = req.GetContent(uri);
        if (_content.empty())
        {
            // 用户请求的资源并不存在
            _status_code = 404;
            req.SetUri(page404);                // 将用户请求的uri直接改成显示404的页面
            _content = req.GetContent(page404); // 重新获取uri对应的内容
        }
        else
        {
            // 请求的资源存在，就不需要修改用户请求的uri
            _status_code = 200;
        }
        _status_desc = Code2Desc(_status_code);
        if (!_content.empty()) // 如果正文部分不为空，就在报头中添加content-length字段
        {
            SetHeader("Content-Length", std::to_string(_content.size())); // 设置Content-Length
        }
        std::string mime_type = Suffix2Desc(req.Suffix());
        SetHeader("Content-Type", mime_type); // 设置Content-Type
        for (auto &[k, v] : _header_kv)
        {
            _resp_headers.push_back(k + HeaderLineSep + v); // 将header_kv中的键值对添加到_resp_headers中
        }
    }
    void Serialize(std::string *resp_str)
    {
        _resp_line = _version + LineSep + std::to_string(_status_code) + LineSep + _status_desc + Sep; // 第一行
        _body = _content;

        // 序列化
        *resp_str = _resp_line;
        for (auto &line : _resp_headers)
        {
            *resp_str += (line + Sep);
        }
        *resp_str += _blank_line;
        *resp_str += _body;
    }
    void SetHeader(const std::string &key, const std::string &value) // 创建key   value 键值对
    {
        _header_kv[key] = value;
    }
    void SetCookie(const std::string &str)
    {
        _resp_headers.push_back(str);
    }

private:
    std::string Code2Desc(int code)
    {
        switch (code)
        {
        case 200:
            return "OK";
        case 404:
            return "Not Found";
        default:
            return "Unknown";
        }
    }
    std::string Suffix2Desc(const std::string &suffix)
    {
        if (suffix == ".html")
        {
            return "text/html";
        }
        else if (suffix == ".jpg")
        {
            return "application/x-jpg";
        }
        else
            return "text/html";
    }
    // 必备的要素
    std::string _version;
    int _status_code;
    std::string _status_desc; // 状态码描述
    std::string _content;
    std::unordered_map<std::string, std::string> _header_kv;
    // 最终要这四部分，构成应答
    std::string _resp_line;
    std::vector<std::string> _resp_headers;
    std::string _blank_line;
    std::string _body;
};